package com.jk.generator;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.IoUtil;
import com.alibaba.fastjson.JSON;
import com.jk.generator.model.*;
import com.jk.generator.model.template.GeneratorInfo;
import com.jk.generator.model.template.TemplateInfo;
import com.jk.generator.utils.DbUtils;
import com.jk.generator.utils.GenUtils;
import com.jk.global.model.exception.BusinessException;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;


import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 代码生成
 */
@Slf4j
public class Generator {


    public static void generate(GeneratorInfoVO vo) throws Exception {

        vo.setPackageName("net.maku")
                .setVersion("1.0.0")
                .setAuthor("xxx")
                .setEmail("xxx@126.com")
                .setTableName("gen_test_member")
                .setTableComment("测试")
                .setClassName("GenTestMember")
                .setConnectUrl("jdbc:mysql://guliyo.top:25336/generator")
                .setConnectUsername("root")
                .setConnectPassword("root");


        //数据模型
        Map<String, Object> dataModel = new HashMap<>();
        //项目信息
        dataModel.put("packageName", vo.getPackageName());
        dataModel.put("packagePath", vo.getPackageName().replace(".", File.separator));
        dataModel.put("version", vo.getVersion());

        dataModel.put("moduleName", vo.getModuleName());
        dataModel.put("backendPath", vo.getBackendPath());
        //开发者信息
        dataModel.put("author", vo.getAuthor());
        dataModel.put("email", vo.getEmail());
        dataModel.put("datetime", LocalDateTimeUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
        dataModel.put("date", LocalDateTimeUtil.format(LocalDate.now(), "yyyy-MM-dd"));
        //表信息
        dataModel.put("tableName", vo.getTableName());
        dataModel.put("tableComment", vo.getTableComment());
        dataModel.put("ClassName", vo.getClassName());
        dataModel.put("className", StringUtils.uncapitalize(vo.getClassName()));
        dataModel.put("classname", vo.getClassName().toLowerCase());

        //初始化配置信息
        DataSourceEntity entity = new DataSourceEntity();
        //数据库名字
        entity.setConnName(vo.getConnectName());
        entity.setConnUrl(vo.getConnectUrl());
        entity.setDbType("MySQL");
        entity.setUsername(vo.getConnectUsername());
        entity.setPassword(vo.getConnectPassword());
        DataSourceInfo dataSourceInfo = getDataSourceInfo(entity);


        //获取原生列数据
        List<TableFieldEntity> tableFieldList = DbUtils.getTableColumns(dataSourceInfo, null, vo.getTableName());
        //初始化列数据
        initFieldList(tableFieldList);
        dataModel.put("columnList", tableFieldList);


        //导入的包列表
        Set<String> imports = tableFieldList.stream()
                .map(TableFieldEntity::getPackageName)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());
        dataModel.put("imports", imports);

        //代码生成器信息
        GeneratorInfo generator = getGeneratorConfig();


        //渲染模板并输出
        for (TemplateInfo template : generator.getTemplates()) {
            dataModel.put("templateName", template.getTemplateName());
            String content = GenUtils.getTemplateContent(template.getTemplateContent(), dataModel);
            String path = GenUtils.getTemplateContent(template.getGeneratorPath(), dataModel);
            //FileUtil.writeUtf8String(content, path);
            FileUtils.writeStringToFile(new File(path), content, "utf-8");
            System.out.println(path);
        }

    }

    public static DataSourceInfo getDataSourceInfo(DataSourceEntity entity) {
        return new DataSourceInfo(entity);
    }

    public static List<FieldTypeEntity> initFieldData() {
        List<FieldTypeEntity> list = new ArrayList<>();
        FieldTypeEntity fieldTypeEntity1 = new FieldTypeEntity();
        fieldTypeEntity1.setAttrType("LocalDateTime");
        fieldTypeEntity1.setPackageName("java.time.LocalDateTime");
        fieldTypeEntity1.setColumnType("datetime");
        list.add(fieldTypeEntity1);

        FieldTypeEntity fieldTypeEntity2 = new FieldTypeEntity();
        fieldTypeEntity2.setAttrType("LocalDate");
        fieldTypeEntity2.setPackageName("java.time.LocalDate");
        fieldTypeEntity2.setColumnType("date");
        list.add(fieldTypeEntity2);

        FieldTypeEntity fieldTypeEntity3 = new FieldTypeEntity();
        fieldTypeEntity3.setColumnType("tinyint");
        fieldTypeEntity3.setAttrType("Integer");
        fieldTypeEntity3.setPackageName(null);
        list.add(fieldTypeEntity3);

        FieldTypeEntity fieldTypeEntity4 = new FieldTypeEntity();
        fieldTypeEntity4.setColumnType("smallint");
        fieldTypeEntity4.setAttrType("Integer");
        fieldTypeEntity4.setPackageName(null);
        list.add(fieldTypeEntity4);

        FieldTypeEntity fieldTypeEntity5 = new FieldTypeEntity();
        fieldTypeEntity5.setColumnType("mediumint");
        fieldTypeEntity5.setAttrType("Integer");
        fieldTypeEntity5.setPackageName(null);
        list.add(fieldTypeEntity5);


        FieldTypeEntity fieldTypeEntity6 = new FieldTypeEntity();
        fieldTypeEntity6.setColumnType("int");
        fieldTypeEntity6.setAttrType("Integer");
        fieldTypeEntity6.setPackageName(null);
        list.add(fieldTypeEntity6);


        FieldTypeEntity fieldTypeEntity7 = new FieldTypeEntity();
        fieldTypeEntity7.setColumnType("integer");
        fieldTypeEntity7.setAttrType("Integer");
        fieldTypeEntity7.setPackageName(null);
        list.add(fieldTypeEntity7);

        FieldTypeEntity fieldTypeEntity8 = new FieldTypeEntity();
        fieldTypeEntity8.setColumnType("bigint");
        fieldTypeEntity8.setAttrType("Long");
        fieldTypeEntity8.setPackageName(null);
        list.add(fieldTypeEntity8);


        FieldTypeEntity fieldTypeEntity9 = new FieldTypeEntity();
        fieldTypeEntity9.setColumnType("float");
        fieldTypeEntity9.setAttrType("Float");
        fieldTypeEntity9.setPackageName(null);
        list.add(fieldTypeEntity9);

        FieldTypeEntity fieldTypeEntity10 = new FieldTypeEntity();
        fieldTypeEntity10.setColumnType("double");
        fieldTypeEntity10.setAttrType("Double");
        fieldTypeEntity10.setPackageName(null);
        list.add(fieldTypeEntity10);

        FieldTypeEntity fieldTypeEntity11 = new FieldTypeEntity();
        fieldTypeEntity11.setColumnType("decimal");
        fieldTypeEntity11.setAttrType("BigDecimal");
        fieldTypeEntity11.setPackageName("java.math.BigDecimal");
        list.add(fieldTypeEntity11);

        FieldTypeEntity fieldTypeEntity12 = new FieldTypeEntity();
        fieldTypeEntity12.setColumnType("bit");
        fieldTypeEntity12.setAttrType("Boolean");
        fieldTypeEntity12.setPackageName(null);
        list.add(fieldTypeEntity12);

        FieldTypeEntity fieldTypeEntity13 = new FieldTypeEntity();
        fieldTypeEntity13.setColumnType("char");
        fieldTypeEntity13.setAttrType("String");
        fieldTypeEntity13.setPackageName(null);
        list.add(fieldTypeEntity13);


        FieldTypeEntity fieldTypeEntity14 = new FieldTypeEntity();
        fieldTypeEntity14.setColumnType("varchar");
        fieldTypeEntity14.setAttrType("String");
        fieldTypeEntity14.setPackageName(null);
        list.add(fieldTypeEntity14);

        FieldTypeEntity fieldTypeEntity15 = new FieldTypeEntity();
        fieldTypeEntity15.setColumnType("tinytext");
        fieldTypeEntity15.setAttrType("String");
        fieldTypeEntity15.setPackageName(null);
        list.add(fieldTypeEntity15);

        FieldTypeEntity fieldTypeEntity16 = new FieldTypeEntity();
        fieldTypeEntity16.setColumnType("text");
        fieldTypeEntity16.setAttrType("String");
        fieldTypeEntity16.setPackageName(null);
        list.add(fieldTypeEntity16);

        FieldTypeEntity fieldTypeEntity17 = new FieldTypeEntity();
        fieldTypeEntity17.setColumnType("mediumtext");
        fieldTypeEntity17.setAttrType("String");
        fieldTypeEntity17.setPackageName(null);
        list.add(fieldTypeEntity17);


        FieldTypeEntity fieldTypeEntity18 = new FieldTypeEntity();
        fieldTypeEntity18.setColumnType("longtext");
        fieldTypeEntity18.setAttrType("String");
        fieldTypeEntity18.setPackageName(null);
        list.add(fieldTypeEntity18);

        FieldTypeEntity fieldTypeEntity19 = new FieldTypeEntity();
        fieldTypeEntity19.setColumnType("timestamp");
        fieldTypeEntity19.setAttrType("LocalDateTime");
        fieldTypeEntity19.setPackageName("java.time.LocalDateTime");
        list.add(fieldTypeEntity19);
        return list;
    }

    public static Map<String, FieldTypeEntity> getFieldTypeMap() {
        List<FieldTypeEntity> list = initFieldData();
        Map<String, FieldTypeEntity> map = new LinkedHashMap<>(list.size());
        for (FieldTypeEntity entity : list) {
            map.put(entity.getColumnType().toLowerCase(), entity);
        }
        return map;
    }


    private static void initFieldList(List<TableFieldEntity> tableFieldList) {
        //字段类型、属性类型映射
        Map<String, FieldTypeEntity> fieldTypeMap = getFieldTypeMap();
        int index = 0;
        for (TableFieldEntity tableField : tableFieldList) {
            tableField.setAttrName(StringUtils.uncapitalize(GenUtils.columnToJava(tableField.getColumnName())));
            //获取字段对应的类型
            FieldTypeEntity fieldTypeMapping = fieldTypeMap.get(tableField.getColumnType().toLowerCase());
            if (fieldTypeMapping == null) {
                //没找到对应的类型，则为Object类型
                tableField.setAttrType("Object");
            } else {
                tableField.setAttrType(fieldTypeMapping.getAttrType());
                tableField.setPackageName(fieldTypeMapping.getPackageName());
            }

            tableField.setList(true);
            tableField.setForm(true);

            tableField.setQueryType("=");
            tableField.setFormType("text");

            tableField.setSort(index++);
        }
    }


    public static GeneratorInfo getGeneratorConfig() {
        // 模板所在路径
        String templatePath = "/template/" + "generator" + "/";

        // 模板配置文件
        //读取模板配置文件
        InputStream isConfig = Generator.class.getResourceAsStream(templatePath + "config.json");
        if (isConfig == null) {
            throw new BusinessException("模板配置文件，config.json不存在");
        }

        // 读取模板配置文件
        String configContent = IoUtil.read(isConfig, StandardCharsets.UTF_8);
        GeneratorInfo info = JSON.parseObject(configContent, GeneratorInfo.class);
        assert info != null;
        for (TemplateInfo templateInfo : info.getTemplates()) {
            // 模板文件
            InputStream isTemplate = Generator.class.getResourceAsStream(templatePath + templateInfo.getTemplateName());
            if (isTemplate == null) {
                throw new BusinessException("模板文件 " + templateInfo.getTemplateName() + " 不存在");
            }
            // 读取模板内容
            String templateContent = IoUtil.read(isTemplate, StandardCharsets.UTF_8);

            templateInfo.setTemplateContent(templateContent);
        }
        return info;
    }
}